<?php

namespace Henan\ThinkSdk\utils;


use Exception;

/**
 * 树形结构工具
 * @author henan
 */
class TreeUtil
{
    /**
     * 实例
     * @var Object
     */
    protected static object $instance;

    /**
     * 列表结构数据
     * @var array
     */
    protected array $list;

    /**
     * 键值对
     * @var array
     */
    protected array $hash;

    /**
     * 根节点ID
     * @var int
     */
    protected int $pid = 0;

    /**
     * 构造方法
     * @param array $list 数组
     * @param int $pid 根节点ID
     * @throws Exception
     */
    public function __construct(array $list = [], int $pid = 0)
    {
        $this->list = $list;
        $this->pid = $pid;
        try {
            $this->hash = array_combine(array_column($list, 'id'), array_column($list, 'pid'));
        } catch (Exception $e) {
            throw new Exception($e->getMessage());
        }
        return $this;
    }

    /**
     * 获取树形结构
     * @return array
     */
    public function getTree(): array
    {
        return self::arrayToTree($this->list, $this->pid);
    }

    /**
     * 单个子级获取父级数组
     * @param int $childrenId
     * @return array
     */
    public function getParent(int $childrenId): array
    {
        $list = [];
        if (isset($this->hash[$childrenId])) {
            $pid = $this->hash[$childrenId];
            if ($pid != $this->pid) {
                $list[] = $pid;
                $newList = $this->getParent($pid);
                $list = array_merge($list, $newList);
            }
        }
        return $list;
    }

    /**
     * 多个子级获取父级数组
     * @param array $childrenIds
     * @return array
     */
    public function getParents(array $childrenIds): array
    {
        $list = $childrenIds;
        foreach ($childrenIds as $id) {
            $parent = $this->getParent($id);
            foreach ($parent as $p) {
                $list[] = $p;
            }
        }
        return array_values(array_unique($list));
    }

    /**
     * 单个父级获取子级数组
     * @param int $parentId
     * @return array
     */
    public function getChildren(int $parentId): array
    {
        static $arr = []; //使用static代替global
        foreach ($this->hash as $id => $pid) {
            if ($pid == $parentId) {
                $arr[] = $id;
                unset($this->hash[$id]); //注销当前节点数据，减少已无用的遍历
                $this->getChildren($id);
            }
        }
        return $arr;
    }

    /**
     * 数组转树形结构
     * @param array $list 数组
     * @param int $pid 父节点ID
     * @return array
     */
    public static function arrayToTree(array $list, int $pid = 0): array
    {
        $tree = [];
        foreach ($list as $v) {
            if ($pid == $v['pid']) {
                $node = $v;
                $child = self::arrayToTree($list, $v['id']);
                if (!empty($child)) {
                    $node['children'] = $child;
                }
                $tree[] = $node;
            }
        }
        return $tree;
    }

    /**
     * 数组转路由结构
     * @param array $list 数组
     * @param int $pid 父节点ID
     * @return array
     */
    public static function arrayToRoute(array $list, int $pid = 0): array
    {
        $tree = [];
        foreach ($list as $item) {
            if ($pid == $item['pid']) {
                $node = [
                    'path' => $item['path'],
                    'name' => $item['name'],
                    'component' => $item['component'],
                    'meta' => ['title' => $item['title'], 'icon' => $item['icon']]
                ];
                !empty($item['redirect']) && $node['redirect'] = $item['redirect'];
                $child = self::arrayToRoute($list, $item['id']);
                if (!empty($child)) {
                    $node['children'] = $child;
                }
                $tree[] = $node;
            }
        }
        return $tree;
    }

    /**
     * 自定义数组转路由结构
     * @param array $list 数组
     * @param int $pid 父节点ID
     * @return array
     */
    public static function customArrayToRoute(array $list, int $pid = 0): array
    {
        $children = [];
        $auths = [];
        foreach ($list as $item) {
            if ($pid == $item['pid']) {
                if ($item['type'] == 2) {
                    $auths[] = $item['auth'];
                } else {
                    $node = [
                        'path' => $item['path'],
                        'name' => $item['name'],
                        'meta' => [
                            'title' => $item['title'],
                            'icon' => $item['icon'],
                            'rank' => $item['rank'] ?? 99,
                            'showLink' => (bool)$item['show_link'],
                            'keepAlive' => $item['keep_alive'],
                            'frameSrc' => $item['frame_src'],
                            'showParent' => true,
                        ]
                    ];
                    [$chs, $aus] = self::customArrayToRoute($list, $item['id']);
                    if ($chs) {
                        $node['children'] = $chs;
                    }
                    if ($aus) {
                        $node['meta']['auths'] = $aus;
                    }
                    $children[] = $node;
                }
            }
        }
        return $pid == 0 ? $children : [$children, $auths];
    }
}